//Copyright (C) 2009 Ron Coleman. Contact: ronncoleman@gmail.com
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 3 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this library; if not, write to the Free Software
//Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301

package org.workplicity.marist.grounds.util;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.workplicity.entry.Service;
import org.workplicity.entry.User;
import org.workplicity.entry.WorkRequest;
import org.workplicity.entry.WorkSlate;
import org.workplicity.entry.event.Daily;
import org.workplicity.entry.event.Monthly;
import org.workplicity.entry.event.Once;
import org.workplicity.entry.event.Recurring;
import org.workplicity.entry.event.Weekdays;
import org.workplicity.entry.event.Weekly;
import org.workplicity.entry.event.Yearly;
import org.workplicity.marist.grounds.worklet.GroundsWorklet;
import org.workplicity.util.Resources;
import org.workplicity.util.WorkDate;
import org.workplicity.worklet.WorkletContext;

/**
 * This is a grounds-specific helper class.
 * @author Ron Coleman
 */
public class GroundsHelper {
    /**
     * Gets the service name associated with an id.
     * @param id Service id
     * @return String
     */
    public static String getSvcName(Integer id) {
        for (Service service : GroundsWorklet.getInstance().getServicesCache().getCache()) {
            if (service.getId().equals(id)) {
                return service.getName();
            }
        }
        return null;
    }

    public static boolean isMy(WorkSlate workslate) {
        return isMy(workslate, GroundsWorklet.getInstance().getContext());
    }

    /**
     * Returns true if the workslate is one of mine.
     * @param workslate
     * @param context
     * @return
     */
    public static boolean isMy(WorkSlate workslate, WorkletContext context) {
        User me = (User) context.read(Resources.TAG_USER);

        for (Integer myId : me.getWorkSlateList()) {
            if (myId.equals(workslate.getId())) {
                return true;
            }
        }

        return false;
    }

    /**
     * Finds the work slate to which this entry (may) belong.
     * Note: assumes entry belongs to exactly one work slate
     * @param entry Order
     * @return work slate
     */
    public static WorkSlate getWorkSlate(WorkRequest request) {
        if(request == null || request.getId() == -1)
            return null;

        ArrayList<WorkSlate> workslates =
                GroundsWorklet.getInstance().getWorkSlatesCache().getCache();

        for (WorkSlate workslate : workslates) {
            for (Integer keyId : workslate.getWorkRequestList()) {
                if (!keyId.equals(request.getId()))
                    continue;

                return workslate;
            }
        }

        return null;
    }

    /**
     * Finds the work slate of an id.
     * @param workSlateId Work slate id
     * @return work slate
     */
    public static WorkSlate getWorkSlate(Integer workSlateId) {
        if(workSlateId == -1)
            return null;
        
        ArrayList<WorkSlate> workslates =
                GroundsWorklet.getInstance().getWorkSlatesCache().getCache();

        for (WorkSlate workslate : workslates) {
            if(workslate.getId().equals(workSlateId))
                return workslate;
        }

        return null;
    }

    /**
     * Gets the logname for a given user id.
     * NOTE: this works only for the grounds worklet.
     * @param id Unique user id.
     * @return Logname of the user.
     */
    public static String getLogname(Integer id) {
        ArrayList<User> users = GroundsWorklet.getInstance().getUsersCache().getCache();

        for (User user : users) {
            if (user.getId().equals(id)) {
                return user.getLogname();
            }
        }

        return "N/A";
    }

    /**
     * Compute the next fire data for a recurring event.
     * @param event Recurring event
     * @return Next fire date
     */
    public static WorkDate getNextFireDate(Recurring event) {
        Calendar cal = Calendar.getInstance();

        // The next firing for once is the start date
        if (event instanceof Once) {
            cal.setTimeInMillis(event.getStarts().getTime());
            cal.set(Calendar.HOUR, 5);
            cal.set(Calendar.MINUTE, 15);
            return new WorkDate(cal.getTimeInMillis());
        }

        // The next firing for the weekdays is the next week day
        if(event instanceof Weekdays) {
            // If the next day is Sun or Sa, then add one
            // or two one days more respectively
            cal.add(Calendar.DATE, 1);

            // Calendar days are Su (1), Mon (2), Tue (3), etc.
            int day = cal.get(Calendar.DAY_OF_WEEK);

            if(day == 1)
                cal.add(Calendar.DATE, 1);

            else if(day == 7)
                cal.add(Calendar.DATE, 2);

            cal.set(Calendar.HOUR, 5);
            cal.set(Calendar.MINUTE, 3);

            return new WorkDate(cal.getTimeInMillis());
        }

        // The next firing for daily is the next day
        if(event instanceof Daily) {
            cal.add(Calendar.DATE, 1);
            cal.set(Calendar.HOUR, 5);
            cal.set(Calendar.MINUTE, 3);

            return new WorkDate(cal.getTimeInMillis());
        }

        // The next firing for monthly is the nearest day of the month
        if(event instanceof Monthly) {
            // Get today
            int today = cal.get(Calendar.DAY_OF_MONTH);

            // Get the scheduled day of the month
            String pattern = event.getPattern();
            int day = Integer.parseInt(pattern.split(" ")[2]);

            // If the month day is in the future, then
            // it is the next firing this month
            // else set it to the same day in the next month
            if(day > today)
                cal.set(Calendar.DAY_OF_MONTH, day);
            else {
                cal.add(Calendar.MONTH, 1);
                cal.set(Calendar.DAY_OF_MONTH, day);
            }

            cal.set(Calendar.HOUR, 5);
            cal.set(Calendar.MINUTE, 5);

            return new WorkDate(cal.getTimeInMillis());
        }

        // The next firing for yearly is the nearest day of the year
        // TODO: the yearly code is buggy and needs to be worked on
        if(event instanceof Yearly) {
            // Get today
            int today = cal.get(Calendar.DAY_OF_YEAR);

            // Get the scheduled day of the year
            String pattern = event.getPattern();
            int day_ = Integer.parseInt(pattern.split(" ")[2]);
            int month = Integer.parseInt(pattern.split(" ")[3]);

            Calendar cal2 = Calendar.getInstance();
            cal2.set(Calendar.DAY_OF_MONTH, day_);
            
            // Months are -1 of actual month
            cal2.set(Calendar.MONTH, month-1);

            int day = cal2.get(Calendar.DAY_OF_YEAR);

            // If the day is in the future, then that day
            // is the day else roll forward one year and its
            // the same day of that year

            // +1 allows for yearly advancement of days
            if((day+1) >= today)
                cal.set(Calendar.DAY_OF_YEAR, day);
            else {
                cal.add(Calendar.YEAR, 1);
                cal.set(Calendar.DAY_OF_YEAR, day);
            }

            cal.set(Calendar.HOUR, 5);
            cal.set(Calendar.MINUTE, 6);

            return new WorkDate(cal.getTimeInMillis());
        }

        return event.getStarts();
    }

    /**
     * Gets all the work slates for a list of unique work slate ids.
     * @param ids Unique work slate ids.
     * @return
     */
    public static ArrayList<WorkSlate> getWorkSlates(List<Integer> ids) {
        ArrayList<WorkSlate> list = new ArrayList<WorkSlate>();

        ArrayList<WorkSlate> workslates = GroundsWorklet.getInstance().getWorkSlatesCache().getCache();

        for (Integer id : ids) {
            for (WorkSlate workslate : workslates) {
                if (workslate.getId().equals(id)) {
                    list.add(workslate);
                }
            }
        }

        return list;
    }

//    /**
//     * Converts a status to a combo box selection index.
//     * @param status Status
//     * @return index
//     */
//    public static int toSelection(WorkRequest.Status status) {
//        if (status == WorkRequest.Status.OPEN) {
//            return 0;
//        } else if (status == WorkRequest.Status.DISPATCHED) {
//            return 1;
//        } else if (status == WorkRequest.Status.CLOSED) {
//            return 2;
//        }
//
//        return 3; //WorkRequest.Status.NA
//    }

    /**
     * Captures the presets from the lines.
     * @param lines Lines
     * @param presets Presets to remove
     * @param suffix
     * @return Lines with presets.
     */
    public static String[] capturePresets(String[]lines, String suffix) {
        ArrayList<String> outputs = new ArrayList<String>( );

        for(int i=0; i < lines.length; i++) {
            if(!lines[i].endsWith(suffix))
                continue;

            // Trim out the number part
            outputs.add(lines[i]);
        }

        // This won't apparently work so we copy the strings into
        // string array
        //return (String[]) outputs.toArray();
        String[] strings = new String[outputs.toArray().length];

        for(int i=0; i < outputs.toArray().length; i++)
            strings[i] = outputs.get(i);

        return strings;
    }

    /**
     * Removes the presets from the lines.
     * @param lines Lines
     * @param presets Presets to remove
     * @param suffix
     * @return Lines without presets.
     */
    public static String[] filterPresets(String[]lines, String suffix) {
        ArrayList<String> outputs = new ArrayList<String>( );

        for(int i=0; i < lines.length; i++) {
            if(lines[i].endsWith(suffix))
                continue;

            // Clean up the lines
            String trimmed = lines[i].trim();

            if(trimmed.length() == 0)
                continue;

            outputs.add(trimmed);
        }

        // This won't apparently work so we copy the strings into
        // string array
        //return (String[]) outputs.toArray();
        String[] strings = new String[outputs.toArray().length];

        for(int i=0; i < outputs.toArray().length; i++)
            strings[i] = outputs.get(i);

        return strings;
    }

    /**
     * Returns true if the status requires a work slate.
     * @param status Status
     * @return True or false
     */
    public static boolean needsWorkSlate(WorkRequest.Status status) {
        if (status == WorkRequest.Status.OPEN || status == WorkRequest.Status.CLOSED) {
            return false;
        }

        return true;
    }
    
    /**
     * Returns true if this is a recurring-type status
     * @param status Status
     * @return True if this is a recurring-type status, false otherwise
     */
    public static boolean isRecurring(WorkRequest.Status status) {
        return status == WorkRequest.Status.RECURRING || status == WorkRequest.Status.PENDING;
    }
}
